package cn.kennylee.codehub.springboot.microtrace.filter;

import cn.kennylee.codehub.springboot.microtrace.TraceContext;
import cn.kennylee.codehub.springboot.microtrace.TraceProperties;
import cn.kennylee.codehub.springboot.microtrace.TraceUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * <p> Servlet微服务请求跟踪过滤器 </p>
 * <p>Created on 2025/4/30.</p>
 *
 * @author kennylee
 * @since 0.0.1
 */
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@RequiredArgsConstructor
public class ServletMicroTraceFilter extends OncePerRequestFilter implements MicroTraceFilter {

    private final TraceProperties traceProperties;

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
                                    @NonNull HttpServletResponse response,
                                    @NonNull FilterChain filterChain) throws ServletException, IOException {

        // 检查是否已经存在 Trace ID
        if (TraceUtils.hasTraceId()) {
            log.warn("当前请求已经存在 Trace ID: {}", MDC.get(traceProperties.getMdcTraceIdName()));
            filterChain.doFilter(request, response);
            return;
        }

        // 1. 从请求头获取或生成 Trace ID
        TraceContext.initFromHttpHeaders(request);

        // 尝试从请求头获取 Trace ID
        String traceId = TraceContext.getTraceId();

        try {
            log.trace("设置 Trace ID: {}", traceId);
            // 将 Trace ID 放入 MDC
            MDC.put(traceProperties.getMdcTraceIdName(), traceId);

            // 添加 Trace ID 到响应头
            response.addHeader(traceProperties.getTraceHeaderName(), traceId);

            filterChain.doFilter(request, response);
        } finally {
            TraceContext.clear();
        }
    }
}
